package altda

import (
	"fmt"
	"net/url"
	"time"

	"github.com/ethereum-optimism/optimism/op-service/cliiface"
	"github.com/urfave/cli/v2"
)

var (
	EnabledFlagName               = altDAFlags("enabled")
	DaServerAddressFlagName       = altDAFlags("da-server")
	VerifyOnReadFlagName          = altDAFlags("verify-on-read")
	DaServiceFlagName             = altDAFlags("da-service")
	PutTimeoutFlagName            = altDAFlags("put-timeout")
	GetTimeoutFlagName            = altDAFlags("get-timeout")
	MaxConcurrentRequestsFlagName = altDAFlags("max-concurrent-da-requests")
)

// altDAFlags returns the flag names for altDA
func altDAFlags(v string) string {
	return "altda." + v
}

func altDAEnvs(envprefix, v string) []string {
	return []string{envprefix + "_ALTDA_" + v}
}

func CLIFlags(envPrefix string, category string) []cli.Flag {
	return []cli.Flag{
		&cli.BoolFlag{
			Name:     EnabledFlagName,
			Usage:    "Enable Alt-DA mode\nAlt-DA Mode is a Beta feature of the MIT licensed OP Stack.  While it has received initial review from core contributors, it is still undergoing testing, and may have bugs or other issues.",
			Value:    false,
			EnvVars:  altDAEnvs(envPrefix, "ENABLED"),
			Category: category,
		},
		&cli.StringFlag{
			Name:     DaServerAddressFlagName,
			Usage:    "HTTP address of a DA Server",
			EnvVars:  altDAEnvs(envPrefix, "DA_SERVER"),
			Category: category,
		},
		&cli.BoolFlag{
			Name:     VerifyOnReadFlagName,
			Usage:    "Verify input data matches the commitments from the DA storage service",
			Value:    true,
			EnvVars:  altDAEnvs(envPrefix, "VERIFY_ON_READ"),
			Category: category,
		},
		&cli.BoolFlag{
			Name:     DaServiceFlagName,
			Usage:    "Use DA service type where commitments are generated by Alt-DA server",
			Value:    false,
			EnvVars:  altDAEnvs(envPrefix, "DA_SERVICE"),
			Category: category,
		},
		&cli.DurationFlag{
			Name:     PutTimeoutFlagName,
			Usage:    "Timeout for put requests. 0 means no timeout.",
			Value:    time.Duration(0),
			EnvVars:  altDAEnvs(envPrefix, "PUT_TIMEOUT"),
			Category: category,
		},
		&cli.DurationFlag{
			Name:     GetTimeoutFlagName,
			Usage:    "Timeout for get requests. 0 means no timeout.",
			Value:    time.Duration(0),
			EnvVars:  altDAEnvs(envPrefix, "GET_TIMEOUT"),
			Category: category,
		},
		&cli.Uint64Flag{
			Name:     MaxConcurrentRequestsFlagName,
			Usage:    "Maximum number of concurrent requests to the DA server",
			Value:    1,
			EnvVars:  altDAEnvs(envPrefix, "MAX_CONCURRENT_DA_REQUESTS"),
			Category: category,
		},
	}
}

type CLIConfig struct {
	Enabled               bool
	DAServerURL           string
	VerifyOnRead          bool
	GenericDA             bool
	PutTimeout            time.Duration
	GetTimeout            time.Duration
	MaxConcurrentRequests uint64
}

func (c CLIConfig) Check() error {
	if c.Enabled {
		if c.DAServerURL == "" {
			return fmt.Errorf("DA server URL is required when altDA is enabled")
		}
		if _, err := url.Parse(c.DAServerURL); err != nil {
			return fmt.Errorf("DA server URL is invalid: %w", err)
		}
	}
	return nil
}

func (c CLIConfig) NewDAClient() *DAClient {
	return &DAClient{url: c.DAServerURL, verify: c.VerifyOnRead, precompute: !c.GenericDA, getTimeout: c.GetTimeout, putTimeout: c.PutTimeout}
}

func ReadCLIConfig(c cliiface.Context) CLIConfig {
	return CLIConfig{
		Enabled:               c.Bool(EnabledFlagName),
		DAServerURL:           c.String(DaServerAddressFlagName),
		VerifyOnRead:          c.Bool(VerifyOnReadFlagName),
		GenericDA:             c.Bool(DaServiceFlagName),
		PutTimeout:            c.Duration(PutTimeoutFlagName),
		GetTimeout:            c.Duration(GetTimeoutFlagName),
		MaxConcurrentRequests: c.Uint64(MaxConcurrentRequestsFlagName),
	}
}
